import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
from PIL import Image, ImageTk
import threading
import os
import sys
import webbrowser
import warnings
import json
from DeepSeek import analyze_news

# 忽略特定的警告
warnings.filterwarnings("ignore", message="pkg_resources is deprecated")

# 添加模块搜索路径（确保找到其他模块）
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

# 导入您的模块
from Login import register, login
from Crawl import crawl_news
from Clear import clean_data
from Analysis import analyze_data
from Visualization import dynamic_visualization
from MongoDB import save_to_mongodb
from FastAPI import run_api


class NewsAnalyzerGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("新闻分析工具")
        self.root.geometry("1000x700")
        self.root.resizable(True, True)

        self.news_data = []
        self.word_freq = []
        self.logged_in = False
        self.user_name = ""

        # 检查用户文件是否存在
        self.check_user_file()

        # 创建样式
        self.style = ttk.Style()
        self.style.configure("TButton", padding=6, font=("微软雅黑", 10))
        self.style.configure("TFrame", background="#f0f0f0")
        self.style.configure("Title.TLabel", font=("微软雅黑", 12, "bold"))

        self.create_auth_panel()
        self.create_main_ui()
        self.switch_to_login()

    def check_user_file(self):
        """检查用户文件是否存在，如果不存在则创建空文件"""
        user_file = 'users.json'
        if not os.path.exists(user_file):
            with open(user_file, 'w') as f:
                json.dump({}, f)
            print("已创建空的用户文件")
        else:
            # 确保文件是有效的JSON格式
            try:
                with open(user_file, 'r') as f:
                    json.load(f)
            except json.JSONDecodeError:
                # 文件损坏，重新创建
                with open(user_file, 'w') as f:
                    json.dump({}, f)

    def create_auth_panel(self):
        """创建认证面板"""
        self.auth_frame = ttk.Frame(self.root)

        # 登录表单
        login_frame = ttk.LabelFrame(self.auth_frame, text="登录", padding=10)
        login_frame.grid(row=0, column=0, padx=20, pady=20, sticky="nsew")

        ttk.Label(login_frame, text="用户名:").grid(row=0, column=0, sticky="w", pady=5)
        self.login_user_entry = ttk.Entry(login_frame, width=25)
        self.login_user_entry.grid(row=0, column=1, padx=5, pady=5)

        ttk.Label(login_frame, text="密码:").grid(row=1, column=0, sticky="w", pady=5)
        self.login_pass_entry = ttk.Entry(login_frame, show="*", width=25)
        self.login_pass_entry.grid(row=1, column=1, padx=5, pady=5)

        login_btn = ttk.Button(login_frame, text="登录", command=self.handle_login)
        login_btn.grid(row=2, column=0, columnspan=2, pady=10)

        # 注册表单
        reg_frame = ttk.LabelFrame(self.auth_frame, text="注册", padding=10)
        reg_frame.grid(row=0, column=1, padx=20, pady=20, sticky="nsew")

        ttk.Label(reg_frame, text="用户名:").grid(row=0, column=0, sticky="w", pady=5)
        self.reg_user_entry = ttk.Entry(reg_frame, width=25)
        self.reg_user_entry.grid(row=0, column=1, padx=5, pady=5)

        ttk.Label(reg_frame, text="密码:").grid(row=1, column=0, sticky="w", pady=5)
        self.reg_pass_entry = ttk.Entry(reg_frame, show="*", width=25)
        self.reg_pass_entry.grid(row=1, column=1, padx=5, pady=5)

        register_btn = ttk.Button(reg_frame, text="注册", command=self.handle_register)
        register_btn.grid(row=2, column=0, columnspan=2, pady=10)

        # 状态标签
        self.status_label = ttk.Label(self.auth_frame, text="状态: 未登录", foreground="red")
        self.status_label.grid(row=1, column=0, columnspan=2, pady=10)

    def create_main_ui(self):
        """创建主界面UI"""
        self.main_frame = ttk.Frame(self.root)

        # 控制面板
        control_frame = ttk.LabelFrame(self.main_frame, text="控制面板", padding=10)
        control_frame.pack(fill=tk.X, padx=10, pady=10)

        # 爬取控制
        self.crawl_btn = ttk.Button(control_frame, text="爬取新闻", command=self.start_crawl)
        self.crawl_btn.grid(row=0, column=0, padx=5)

        self.clean_btn = ttk.Button(control_frame, text="清洗数据", state="disabled", command=self.start_clean)
        self.clean_btn.grid(row=0, column=1, padx=5)

        self.analyze_btn = ttk.Button(control_frame, text="分析数据", state="disabled", command=self.start_analyze)
        self.analyze_btn.grid(row=0, column=2, padx=5)

        self.visualize_btn = ttk.Button(control_frame, text="动态可视化", state="disabled",
                                        command=self.show_visualization)
        self.visualize_btn.grid(row=0, column=3, padx=5)

        self.api_btn = ttk.Button(control_frame, text="启动API服务", command=self.start_api)
        self.api_btn.grid(row=0, column=4, padx=5)

        self.deepseek_btn = ttk.Button(control_frame, text="DeepSeek总结", command=self.start_deepseek_analysis)
        self.deepseek_btn.grid(row=0, column=5, padx=5)

        # 结果显示区域 - 标签页
        self.notebook = ttk.Notebook(self.main_frame)
        self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 新闻数据标签页
        self.news_tab = ttk.Frame(self.notebook)
        self.notebook.add(self.news_tab, text="新闻数据")

        self.news_table = ttk.Treeview(self.news_tab, columns=("title", "link"), show="headings")
        self.news_table.heading("title", text="标题")
        self.news_table.heading("link", text="链接")
        self.news_table.column("title", width=350)
        self.news_table.column("link", width=450)

        scrollbar = ttk.Scrollbar(self.news_tab, orient=tk.VERTICAL, command=self.news_table.yview)
        self.news_table.configure(yscroll=scrollbar.set)

        self.news_table.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # 词频分析标签页
        self.word_tab = ttk.Frame(self.notebook)
        self.notebook.add(self.word_tab, text="词频分析")

        # 创建分割窗口（上半部分显示词频，下半部分显示DeepSeek总结）
        paned_window = ttk.PanedWindow(self.word_tab, orient=tk.VERTICAL)
        paned_window.pack(fill=tk.BOTH, expand=True)

        table_frame = ttk.Frame(paned_window)
        paned_window.add(table_frame, weight=1)

        self.word_table = ttk.Treeview(self.word_tab, columns=("word", "count"), show="headings")
        self.word_table.heading("word", text="词语")
        self.word_table.heading("count", text="出现次数")
        self.word_table.column("word", width=200)
        self.word_table.column("count", width=100)

        scrollbar_word = ttk.Scrollbar(self.word_tab, orient=tk.VERTICAL, command=self.word_table.yview)
        self.word_table.configure(yscroll=scrollbar_word.set)

        self.word_table.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar_word.pack(side=tk.RIGHT, fill=tk.Y)

        summary_frame = ttk.Frame(paned_window)
        paned_window.add(summary_frame, weight=1)

        ttk.Label(summary_frame, text="DeepSeek新闻总结:", font=("微软雅黑", 10, "bold")).pack(anchor=tk.W, padx=5,
                                                                                               pady=5)

        self.summary_text = scrolledtext.ScrolledText(
            summary_frame,
            height=8,
            font=("微软雅黑", 10)
        )
        self.summary_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        self.summary_text.config(state=tk.DISABLED)

        # 词云图标签页
        self.cloud_tab = ttk.Frame(self.notebook)
        self.notebook.add(self.cloud_tab, text="词云图")

        self.cloud_label = ttk.Label(self.cloud_tab)
        self.cloud_label.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 日志区域
        log_frame = ttk.LabelFrame(self.main_frame, text="操作日志", padding=5)
        log_frame.pack(fill=tk.X, padx=10, pady=5)

        self.log_area = scrolledtext.ScrolledText(log_frame, height=5)
        self.log_area.pack(fill=tk.BOTH, expand=True)
        self.log_area.config(state=tk.DISABLED)

        # 状态栏
        self.main_status = ttk.Label(self.main_frame, text="就绪", relief=tk.SUNKEN, anchor=tk.W)
        self.main_status.pack(side=tk.BOTTOM, fill=tk.X)

    def switch_to_login(self):
        """显示登录界面"""
        if hasattr(self, 'main_frame'):
            self.main_frame.pack_forget()
        self.auth_frame.pack(fill=tk.BOTH, expand=True)

    def switch_to_main(self):
        """显示主界面"""
        self.auth_frame.pack_forget()
        self.main_frame.pack(fill=tk.BOTH, expand=True)

        username = self.user_name
        self.logged_in = True
        self.update_status(f"已登录用户: {username}")

    def update_status(self, message):
        """更新状态栏信息"""
        self.main_status.config(text=f"状态: {message}")

    def log_message(self, message):
        """记录日志消息"""
        self.log_area.config(state=tk.NORMAL)
        self.log_area.insert(tk.END, message + "\n")
        self.log_area.see(tk.END)  # 滚动到底部
        self.log_area.config(state=tk.DISABLED)

    def handle_login(self):
        """处理登录操作"""
        username = self.login_user_entry.get()
        password = self.login_pass_entry.get()

        if not username or not password:
            messagebox.showerror("错误", "用户名和密码不能为空!")
            return

        # 调用登录模块 - 传递用户名和密码
        if login(username, password):
            self.user_name = username
            self.status_label.config(text="登录成功!", foreground="green")
            self.log_message(f"{username} 登录成功")
            self.switch_to_main()
        else:
            messagebox.showerror("登录失败", "用户名或密码错误")

    def handle_register(self):
        """处理注册操作"""
        username = self.reg_user_entry.get()
        password = self.reg_pass_entry.get()

        if not username or not password:
            messagebox.showerror("错误", "用户名和密码不能为空!")
            return

        # 调用注册模块 - 传递用户名和密码
        if register(username, password):
            messagebox.showinfo("注册成功", "注册成功，请登录!")
            self.reg_user_entry.delete(0, tk.END)
            self.reg_pass_entry.delete(0, tk.END)
            self.log_message(f"新用户 {username} 注册成功")
        else:
            messagebox.showerror("注册失败", "该用户名已被使用")

    def start_crawl(self):
        """启动爬取线程"""
        self.update_status("正在爬取新闻...")
        self.log_message("开始爬取新闻数据")
        self.crawl_btn.config(state="disabled")

        # 在后台线程中执行爬取操作
        threading.Thread(target=self.crawl_thread, daemon=True).start()

    def crawl_thread(self):
        """爬取线程"""
        try:
            self.news_data = crawl_news()

            # 更新UI
            self.root.after(0, self.show_news_data)
            self.root.after(0, lambda: self.clean_btn.config(state="normal"))
            self.root.after(0, lambda: self.update_status("新闻爬取完成!"))
            self.root.after(0, lambda: self.log_message(f"成功爬取 {len(self.news_data)} 条新闻"))
        except Exception as e:
            self.root.after(0, lambda: self.update_status(f"爬取失败: {str(e)}"))
            self.root.after(0, lambda: self.log_message(f"爬取失败: {str(e)}"))
            self.root.after(0, lambda: self.crawl_btn.config(state="normal"))

    def show_news_data(self):
        """显示新闻数据"""
        # 清空现有表格
        for row in self.news_table.get_children():
            self.news_table.delete(row)

        # 添加新数据
        for news in self.news_data:
            self.news_table.insert("", "end", values=(news.get("title", ""), news.get("link", "")))

        self.crawl_btn.config(state="normal")

    def start_clean(self):
        """启动数据清洗线程"""
        self.update_status("正在清洗数据...")
        self.log_message("开始清洗新闻数据")
        self.clean_btn.config(state="disabled")

        threading.Thread(target=self.clean_thread, daemon=True).start()

    def clean_thread(self):
        """清洗线程"""
        try:
            cleaned_data = clean_data(self.news_data)
            self.news_data = cleaned_data

            self.root.after(0, self.show_news_data)
            self.root.after(0, lambda: self.analyze_btn.config(state="normal"))
            self.root.after(0, lambda: self.update_status(f"清洗完成，有效数据: {len(self.news_data)}条"))
            self.root.after(0, lambda: self.log_message(f"数据清洗完成，保留 {len(self.news_data)} 条有效新闻"))
        except Exception as e:
            self.root.after(0, lambda: self.update_status(f"清洗失败: {str(e)}"))
            self.root.after(0, lambda: self.log_message(f"数据清洗失败: {str(e)}"))
            self.root.after(0, lambda: self.clean_btn.config(state="normal"))

    def start_analyze(self):
        """启动分析线程"""
        self.update_status("正在分析数据...")
        self.log_message("开始分析新闻数据")
        self.analyze_btn.config(state="disabled")

        threading.Thread(target=self.analyze_thread, daemon=True).start()

    def analyze_thread(self):
        """分析线程"""
        try:
            if not self.news_data:
                self.root.after(0, lambda: messagebox.showerror("错误", "没有可分析的数据"))
                return

            # 调用分析模块
            top_words = analyze_data(self.news_data)
            self.word_freq = top_words

            # 更新UI
            self.root.after(0, self.show_word_freq)
            self.root.after(0, self.show_wordcloud)
            self.root.after(0, lambda: self.visualize_btn.config(state="normal"))
            self.root.after(0, lambda: self.update_status("分析完成"))
            self.root.after(0, lambda: self.log_message("数据分析完成"))
        except Exception as e:
            self.root.after(0, lambda: self.update_status(f"分析失败: {str(e)}"))
            self.root.after(0, lambda: self.log_message(f"数据分析失败: {str(e)}"))
            self.root.after(0, lambda: self.analyze_btn.config(state="normal"))

    def show_word_freq(self):
        """显示词频数据"""
        # 清空现有表格
        for row in self.word_table.get_children():
            self.word_table.delete(row)

        # 添加新数据
        for word, count in self.word_freq:
            self.word_table.insert("", "end", values=(word, count))

    def show_wordcloud(self):
        """显示词云图"""
        try:
            img_path = "wordcloud.png"
            if not os.path.exists(img_path):
                self.log_message("词云图文件不存在")
                return

            # 加载并显示词云图
            img = Image.open(img_path)
            img = img.resize((700, 500), Image.Resampling.LANCZOS)
            photo = ImageTk.PhotoImage(img)

            self.cloud_label.configure(image=photo)
            self.cloud_label.image = photo  # 保持引用
            self.log_message("词云图已加载")
        except Exception as e:
            self.log_message(f"显示词云图失败: {str(e)}")

    def show_visualization(self):
        """显示动态可视化图表"""
        try:
            # 生成可视化图表
            dynamic_visualization(self.news_data)

            # 在浏览器中打开
            html_path = os.path.abspath("timeline.html")
            self.log_message(f"在浏览器中打开: file:///{html_path}")
            webbrowser.open(f"file:///{html_path}")
            self.log_message("动态可视化图表已生成")
        except Exception as e:
            self.log_message(f"生成可视化图表失败: {str(e)}")

    def start_api(self):
        """启动API服务"""
        self.update_status("正在启动API服务...")
        self.log_message("启动FastAPI服务")

        threading.Thread(target=self.api_thread, daemon=True).start()

    def api_thread(self):
        """API服务线程"""
        try:
            self.log_message("API服务在 http://localhost:8000/news 上运行")
            self.log_message("按CTRL+C停止服务")
            self.root.after(0, lambda: self.update_status("API服务运行中..."))

            # 调用启动函数
            run_api()
        except Exception as e:
            self.root.after(0, lambda: self.update_status(f"API服务启动失败: {str(e)}"))
            self.root.after(0, lambda: self.log_message(f"API服务启动失败: {str(e)}"))

    # 在 NewsAnalyzerGUI 类中添加以下方法
    def start_deepseek_analysis(self):
        """启动DeepSeek分析线程"""
        if not self.news_data:
            messagebox.showerror("错误", "请先爬取并分析数据！")
            return

        self.update_status("正在使用DeepSeek分析...")
        self.log_message("开始DeepSeek分析")
        self.deepseek_btn.config(state="disabled")

        # 启动线程
        threading.Thread(target=self.deepseek_analysis_thread, daemon=True).start()

    def deepseek_analysis_thread(self):
        """DeepSeek分析线程"""
        try:
            # 调用DeepSeek模块分析新闻数据
            summary = analyze_news(self.news_data)

            # 更新UI
            self.root.after(0, lambda: self.show_deepseek_summary(summary))
            self.root.after(0, lambda: self.update_status("DeepSeek分析完成"))
            self.root.after(0, lambda: self.log_message("DeepSeek分析完成"))
        except Exception as e:
            self.root.after(0, lambda: self.update_status(f"DeepSeek分析失败: {str(e)}"))
            self.root.after(0, lambda: self.log_message(f"DeepSeek分析失败: {str(e)}"))
        finally:
            self.root.after(0, lambda: self.deepseek_btn.config(state="normal"))

    def show_deepseek_summary(self, summary):
        """显示DeepSeek分析结果"""
        # 切换到词频分析标签页
        self.notebook.select(self.word_tab)

        # 更新总结文本
        self.summary_text.config(state=tk.NORMAL)
        self.summary_text.delete(1.0, tk.END)
        self.summary_text.insert(tk.END, summary)
        self.summary_text.config(state=tk.DISABLED)

        # 滚动到顶部
        self.summary_text.see(tk.END)


if __name__ == "__main__":
    root = tk.Tk()
    gui = NewsAnalyzerGUI(root)
    root.mainloop()
    # 最终版